package com.android.monee.data.access.json;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import com.android.monee.data.access.IdNClone;
import com.android.monee.data.access.inMemory.AbstractObservableDaoInMemory;
import com.android.monee.data.model.Budget;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.MapType;
import com.fasterxml.jackson.databind.type.TypeFactory;


public abstract class AbstractObservableDaoJson<T extends IdNClone<I, T>, I> extends
		AbstractObservableDaoInMemory<T, I> {

	private ObjectMapper mapper;
	private File dataFile;
	private File backupFile;
	private String rootDir;
	private boolean prepared = false;
	
	public void init(String rootDir, Class<T> tKlass, Class<I> iKlass) {
		this.mapper = new ObjectMapper();
		
		this.rootDir = rootDir;
		
		//this.mapper.configure(MapperFeature.USE_STATIC_TYPING, true);
		this.dataFile = new File(rootDir, tKlass.getCanonicalName()+".json");
		this.backupFile = new File(rootDir, tKlass.getCanonicalName()+".bak");
		
		System.out.println("init Json dao, dataFile is "+this.dataFile.getAbsolutePath()+" exists="+this.dataFile.exists());
		try {
			if(!this.dataFile.exists()){
				this.dataFile.createNewFile();

				super.datas = new HashMap<I, T>();
			}
			else{
				BufferedReader bf = new BufferedReader(new FileReader(this.dataFile));
				String line = bf.readLine();
				System.out.println("Contenu du fichier lu :");
				while(line != null){
					System.out.println(line);
					line = bf.readLine();
				}
				
				//TODO : bug dans jackson ?
//				Map<I, T> persistedDatas = this.mapper.readValue(
//						this.dataFile,
//						new TypeReference<Map<I, T>>() {
//						});

				TypeFactory tf = mapper.getTypeFactory();
				MapType mapType = tf.constructMapType(HashMap.class, iKlass, tKlass);
				
				Map<I, T> persistedDatas = this.mapper.readValue(
						this.dataFile,
						mapType);
				
				super.datas = persistedDatas;
			}
		} catch (JsonParseException e2) {
			e2.printStackTrace();
		} catch (JsonMappingException e2) {
			e2.printStackTrace();
		} catch (IOException e2) {
			e2.printStackTrace();
		}
		
		this.prepared = true;
	}
	
	@Override
	public void insert(T obj) {
		super.insert(obj);
		this.persist();
	}


	@Override
	public void update(T obj) {
		super.update(obj);
		this.persist();
	}


	@Override
	public void delete(I id) {
		super.delete(id);
		this.persist();
	}

	protected void persist(){
		try {
			if(!this.prepared)
				throw new IllegalStateException("Pensez à appeler la méthode init() avant d'invoquer persist()");
			
			if(!this.backupFile.exists())
				this.backupFile.createNewFile();
			
			//ObjectWriter writer = this.mapper.writerWithType(new TypeReference<Map<I, T>>(){});
			//writer.writeValue(this.backupFile, super.datas);
			//<I, T> map = new HashMap<I, T>(super.datas);
			this.mapper.writeValue(this.backupFile, super.datas);
			//this.mapper.writeValue(this.backupFile, map);
				
			BufferedReader bf = new BufferedReader(new FileReader(this.backupFile));
			String line = bf.readLine();
			System.out.println("Contenu du fichier écrit :");
			while(line != null){
				System.out.println(line);
				line = bf.readLine();
			}
			
			if(this.dataFile.delete())
				if(this.backupFile.renameTo(this.dataFile))
					return;
				else
					throw new IOException("Rename "+this.backupFile.getAbsolutePath()+" to "+this.dataFile+" failed.");
			else
				throw new IOException("Delete "+this.dataFile+" failed.");
		} catch (JsonGenerationException e) {
			e.printStackTrace();
		} catch (JsonMappingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
